import React, { ChangeEvent, FC, useRef, useState } from 'react';
import axios from 'axios';
import UploadList from './uploadList';
import Dragger from './dragger';

export type UploadFileStatus = 'ready' | 'uploading' | 'success' | 'error';

export interface UploadFile {
  uid: string;
  size: number;
  name: string;
  status?: UploadFileStatus;
  percent?: number; 
  raw?: File;
  response?: any;
  error?: any;
}

// name 属性 - 代表发到后台文件参数名称
// data 属性 - 上传所需的额外参数
// withCredentials 跨域是否携带 cookie
// input 本身的 file 约束属性 - multiple 多选,
// accept 限制上传文件的的类型 appect="image/png" 或 appect="png"

export interface UploadProps {
  action: string;
  defaultFileList?: UploadFile[];
  beforeUpload?: (file: File) => boolean | Promise<File>;
  onProgress?: (percentage: number, file:UploadFile) => void;
  onSuccess?: (data: any, file: UploadFile) => void;
  onError?: (err: any, file: UploadFile) => void;
  onChange?: (file: UploadFile) => void;
  onRemove?: (file: UploadFile) => void;
  headers?: { [key: string]: any };
  name?: string;
  data?: { [key: string]: any };
  withCredentials?: boolean;
  accept?: string;
  multiple?: boolean;
  drag?: boolean;
  style?: React.CSSProperties;
}

export const Upload: FC<UploadProps> = (props) => {
  const {
    children,
    action,
    beforeUpload,
    onProgress,
    onSuccess,
    onError,
    onChange,
    onRemove,
    defaultFileList,
    headers,
    name,
    data,
    withCredentials,
    accept,
    multiple,
    drag,
    style,
  } = props;
  
  const fileInput = useRef<HTMLInputElement>(null);
  const [fileList, setFileList] = useState<UploadFile[]>(defaultFileList || []);
  // 异步修改 fileList
  const updateFileList = (updateFile: UploadFile, updateObj: Partial<UploadFile>) => {
    setFileList(prevFileList => {
      console.log(prevFileList);
      return prevFileList.map(file => {
        if (file.uid === updateFile.uid) {
          return { ...file, ...updateObj };
        } else {
          return file;
        }
      })
    })
  }

  const handleClick = () => {
    if (fileInput.current) {
      fileInput.current.click();
    }
  }
  
  const inputFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files) {
      return;
    }
    uploadFiles(files);
    if(fileInput.current) {
      fileInput.current.value = '';
    }
  }

  // 删除文件列表中的元素
  const uploadListRemove = (file: UploadFile) => {
    setFileList((prevList) => {
      return prevList.filter(item => item.uid !== file.uid);
    })
    if (onRemove) {
      onRemove(file);
    }
  }

  const uploadFiles = (files: FileList) => {
    let postFiles = Array.from(files);
    postFiles.forEach(file => {
      if (!beforeUpload) {
        post(file);
      } else {
        const result = beforeUpload(file);
        if (result && result instanceof Promise) {
          result.then(processedFile => {
            post(processedFile);
          });
        } else if (result) {
          post(file);
        }
      }
    });
  }

  const post = (file: File) => {
    let _file: UploadFile = {
      uid: Date.now() + file.name +'upload-file',
      status: 'ready',
      name: file.name,
      size: file.size,
      percent: 0,
      raw: file
    }
    // setFileList([_file, ...fileList]);
    setFileList(prevList => {
      return [_file, ...prevList];
    })
    const formData = new FormData();
    formData.append(name || 'file', file);
    if (data) {
      Object.keys(data).forEach(key => {
        formData.append(key, data[key])
      })
    }
    axios.post(action, formData, {
      headers: {
        ...headers,
        'Content-Type': 'multipart/form-data'
      },
      withCredentials,
      onUploadProgress: (e: any) => {
        let percentage = Math.round((e.loaded * 100 / e.total)) || 0;
        if (percentage < 100 ) {
          updateFileList(_file, { status: 'uploading',percent: percentage });
          if (onProgress) {
            onProgress(percentage, _file);
          }
         }
      }
    }).then(resp => {
      // console.log('success');
      updateFileList(_file, { status: 'success', response: resp.data })
      if (onSuccess) {
        onSuccess(resp.data,  _file);
      }
      if (onChange) {
        onChange(_file);
      }
    }).catch(err => {
      // console.log('err');
      updateFileList(_file, { status: 'error', error: err })
      if (onError) {
        onError(err, _file);
      }
      if (onChange) {
        onChange( _file);
      }
    })
  }

  return (<div className="origin-upload-component" style={style}>
      <div className="origin-upload-input"
        style={{ display: 'inline-block' }}
        onClick={handleClick}
      >
      {drag ? <Dragger onFile={(files) => { uploadFiles(files) }}>{ children}</Dragger> : children}
        <input
          className="origin-file-input"
          style={{ display: 'none' }}
          ref={fileInput}
          type="file"
          onChange={inputFileChange}
          accept={accept}
          multiple={multiple}
        ></input>
      </div>
    <UploadList fileList={fileList} onRemove={uploadListRemove}>
    </UploadList>
  </div>)
}

Upload.defaultProps = {
  name: 'file'
}
export default Upload;